/*
 * Copyright (c) 2008, 2023 Oracle and/or its affiliates. All rights reserved.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v. 2.0 which is available at
 * http://www.eclipse.org/legal/epl-2.0,
 * or the Eclipse Distribution License v. 1.0 which is available at
 * http://www.eclipse.org/org/documents/edl-v10.php.
 *
 * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
 */

// Contributors:
//     Petros Splinakis - 2.2
//     Linda DeMichiel - 2.1
//     Linda DeMichiel - 2.0

package jakarta.persistence;

import java.lang.annotation.Repeatable;
import java.lang.annotation.Target;
import java.lang.annotation.Retention;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

/**
 * Specifies a mapping to an entity that is a map key. The map key join
 * column is in the collection table, join table, or table of the target
 * entity that is used to represent the map. If no {@code MapKeyJoinColumn}
 * annotation is specified, a single join column is assumed and the default
 * values apply.
 *
 * <p>Example 1:
 * {@snippet :
 * @Entity
 * public class Company {
 *     @Id
 *     int id;
 *     ...
 *     @OneToMany   // unidirectional
 *     @JoinTable(name = "COMPANY_ORGANIZATION",
 *                joinColumns = @JoinColumn(name = "COMPANY"),
 *                inverseJoinColumns = @JoinColumn(name = "VICEPRESIDENT"))
 *     @MapKeyJoinColumn(name = "DIVISION")
 *     Map<Division, VicePresident> organization;
 * }
 * }
 *
 * <p>Example 2:
 * {@snippet :
 * @Entity
 * public class VideoStore {
 *     @Id
 *     int id;
 *     String name;
 *     Address location;
 *     ...
 *     @ElementCollection
 *     @CollectionTable(name = "INVENTORY",
 *                      joinColumns = @JoinColumn(name = "STORE"))
 *     @Column(name = "COPIES_IN_STOCK")
 *     @MapKeyJoinColumn(name = "MOVIE", referencedColumnName = "ID")
 *     Map<Movie, Integer> videoInventory;
 *     ...
 * }
 *
 * @Entity
 * public class Movie {
 *     @Id long id;
 *     String title;
 *     ...
 * }
 * }
 *
 * <p>Example 3:
 * {@snippet :
 * @Entity
 * public class Student {
 *     @Id
 *     int studentId;
 *     ...
 *     @ManyToMany  // students and courses are also many-many
 *     @JoinTable(name = "ENROLLMENTS",
 *                joinColumns = @JoinColumn(name = "STUDENT"),
 *                inverseJoinColumns = @JoinColumn(name = "SEMESTER"))
 *     @MapKeyJoinColumn(name = "COURSE")
 *     Map<Course, Semester> enrollment;
 *     ...
 * }
 * }
 *
 * @see ForeignKey
 *
 * @since 2.0
 */
@Repeatable(MapKeyJoinColumns.class)
@Target( { METHOD, FIELD })
@Retention(RUNTIME)
public @interface MapKeyJoinColumn {
    /**
     * (Optional) The name of the foreign key column for the map key.
     * The table in which it is found depends upon the context.
     * <ul> 
     * <li> If the join is for a map key for an element collection,
     *      the foreign key column is in the collection table for the
     *      map value.
     * <li> If the join is for a map key for a {@link ManyToMany}
     *      entity relationship or for a {@link OneToMany} entity
     *      relationship using a join table, the foreign key column
     *      is in a join table.
     * <li> If the join is for a {@link OneToMany} entity relationship
     *      using a foreign key mapping strategy, the foreign key column
     *      for the map key is in the table of the entity that is the
     *      value of the map.
     * </ul>
     *
     * <p> Default (only applies if a single join column is used.)
     * The concatenation of the following: the name of the referencing
     * relationship property or field of the referencing entity or
     * embeddable class; "{@code _}"; "{@code KEY}".
     */
    String name() default "";

    /**
     * (Optional) The name of the column referenced by this foreign key
     * column. The referenced column is in the table of the target entity.
     *
     * <p> Default (only applies if single join column is being used.)
     * The same name as the primary key column of the referenced table.
     */
    String referencedColumnName() default "";

    /**
     * (Optional) Whether the property is a unique key. This is a
     * shortcut for the {@link UniqueConstraint} annotation at the
     * table level and is useful for when the unique key constraint
     * is only a single field.
     */
    boolean unique() default false;

    /**
     * (Optional) Whether the foreign key column is nullable.
     */
    boolean nullable() default false;

    /**
     * (Optional) Whether the column is included in SQL INSERT
     * statements generated by the persistence provider.
     */
    boolean insertable() default true;

    /**
     * (Optional) Whether the column is included in SQL UPDATE
     * statements generated by the persistence provider.
     */
    boolean updatable() default true;

    /**
     * (Optional) The SQL fragment that is used when generating
     * the DDL for the column.
     * Defaults to SQL generated by the provider for the column.
     */
    String columnDefinition() default "";
    
    /**
     * (Optional) A SQL fragment appended to the generated DDL
     * which declares this column. May not be used in
     * conjunction with {@link #columnDefinition()}.
     *
     * @since 3.2
     */
    String options() default "";
    
    /**
     * (Optional) The name of the table that contains the foreign
     * key column.
     * <ul>
     * <li> If the join is for a map key for an element collection,
     *      the foreign key column is in the collection table for
     *      the map value.
     * <li> If the join is for a map key for a {@link ManyToMany}
     *      entity relationship or for a {@link OneToMany} entity
     *      relationship using a join table, the foreign key column
     *      is in a join table.
     * <li> If the join is for a {@link OneToMany} entity relationship
     *      using a foreign key mapping strategy, the foreign key column
     *      for the map key is in the table of the entity that is the
     *      value of the map.
     * </ul>
     *
     * <p> Default: 
     * <ul>
     * <li> If the map is for an element collection, the name of the
     *      collection table for the map value.
     * <li> If the map is for a {@link OneToMany} or {@link ManyToMany}
     *      entity relationship using a join table, the name of the join
     *      table for the map.
     * <li> If the map is for a {@link OneToMany} entity relationship
     *      using a foreign key mapping strategy, the name of the primary
     *      table of the entity that is the value of the map.
     * </ul>
     */
    String table() default "";

    /**
     * (Optional) Used to specify or control the generation of a
     * foreign key constraint when table generation is in effect.
     * If this element is not specified, a default foreign key
     * strategy is selected by the persistence provider.
     *
     * @since 2.1
     */
    ForeignKey foreignKey() default @ForeignKey(ConstraintMode.PROVIDER_DEFAULT);
}
